<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>声学无人机监测</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <style type="text/css">
        html, body {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            font-family: Arial, sans-serif;
        }
        #map_container {
            width: 100%;
            height: 100%;
            margin: 0;
        }
        #tools {
            position: absolute;
            background: rgba(0, 0, 0, 0.7);
            padding: 10px;
            z-index: 100;
            right: 10px;
            bottom: 10px;
            color: #fff;
            border-radius: 5px;
        }
        #tools button {
            width: 120px;
            height: 35px;
            background: #1E90FF;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            margin: 5px 0;
        }
        #tools button:hover {
            background: #187bcd;
        }
        /* 麦克风矩阵坐标显示 */
        #radar-coords {
            position: absolute;
            background: rgba(0, 0, 0, 0.7);
            padding: 10px;
            z-index: 100;
            right: 10px;
            top: 10px;
            color: #fff;
            border-radius: 5px;
            font-size: 12px;
        }
        #radar-coords div {
            margin: 3px 0;
        }
        /* 左侧控制面板样式 */
        #control-panel {
            position: absolute;
            left: 10px;
            top: 10px;
            width: 320px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 15px;
            border-radius: 5px;
            z-index: 100;
            box-shadow: 0 2px 10px rgba(0,0,0,0.5);
        }
        .panel-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            border-bottom: 1px solid #444;
            padding-bottom: 10px;
        }
        .panel-title {
            font-size: 18px;
            font-weight: bold;
        }
        .timestamp {
            font-size: 16px;
            color: #1E90FF;
        }
        .current-data {
            margin: 15px 0;
            padding: 10px;
            background: rgba(255,255,255,0.1);
            border-radius: 3px;
        }
        .data-item {
            display: flex;
            justify-content: space-between;
            margin: 8px 0;
        }
        .data-label {
            color: #aaa;
        }
        .data-value {
            font-weight: bold;
        }
        .btn-group {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            margin: 10px 0;
        }
        .btn {
            padding: 8px 12px;
            background: #1E90FF;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            flex: 1;
            min-width: 70px;
            font-size: 12px;
        }
        .btn:hover {
            background: #187bcd;
        }
        .btn-danger {
            background: #dc3545;
        }
        .btn-danger:hover {
            background: #c82333;
        }
        .btn-success {
            background: #28a745;
        }
        .btn-success:hover {
            background: #218838;
        }
        #data-log {
            max-height: 250px;
            overflow-y: auto;
            margin-top: 15px;
            font-size: 12px;
        }
        #data-log table {
            width: 100%;
            border-collapse: collapse;
        }
        #data-log th {
            background: rgba(30, 144, 255, 0.3);
            position: sticky;
            top: 0;
        }
        #data-log th, #data-log td {
            border: 1px solid #444;
            padding: 6px;
            text-align: left;
        }
        #data-log tr:nth-child(even) {
            background: rgba(255,255,255,0.05);
        }
        /* 滚动条样式 */
        #data-log::-webkit-scrollbar {
            width: 6px;
        }
        #data-log::-webkit-scrollbar-track {
            background: rgba(0,0,0,0.1);
        }
        #data-log::-webkit-scrollbar-thumb {
            background: #1E90FF;
            border-radius: 3px;
        }
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?type=webgl&v=1.0&ak=Mm5NSaQUXKP52Eqa89DplvZmik4Sxp3a"></script>
    <script type="text/javascript" src="https://mapv.baidu.com/gl/examples/static/common.js"></script>
    <script type="text/javascript" src="https://mapopen-pub-jsapigl.bj.bcebos.com/newThree/three.min.js"></script>
    <script type="text/javascript" src="https://code.bdstatic.com/npm/mapvgl@1.0.0-beta.151/dist/mapvgl.min.js"></script>
    <script type="text/javascript" src="https://code.bdstatic.com/npm//mapvgl@1.0.0-beta.151/dist/mapvgl.threelayers.min.js"></script>
</head>

<body>
    <div id="map_container"></div>
    <div id="tools">
        <button onclick="targetToFly()">跟踪无人机</button>
        <button onclick="toggleFlightPath()">显示完整轨迹</button>
    </div>
    
    <!-- 麦克风矩阵坐标显示 -->
    <div id="radar-coords">
        <div>麦克风矩阵坐标:</div>
        <div id="radar-lng">经度: -</div>
        <div id="radar-lat">纬度: -</div>
        <div id="radar-alt">高度: 0 米</div>
    </div>
    
    <!-- 左侧控制面板 -->
    <div id="control-panel">
        <div class="panel-header">
            <div class="panel-title">声学无人机监测</div>
            <div class="timestamp" id="current-time">--:--:--</div>
        </div>
        
        <div class="current-data">
            <div class="data-item">
                <span class="data-label">经度:</span>
                <span class="data-value" id="current-lng">-</span>
            </div>
            <div class="data-item">
                <span class="data-label">纬度:</span>
                <span class="data-value" id="current-lat">-</span>
            </div>
            <div class="data-item">
                <span class="data-label">高度:</span>
                <span class="data-value" id="current-alt">-</span>
            </div>
            <div class="data-item">
                <span class="data-label">距离麦克风矩阵:</span>
                <span class="data-value" id="current-dist">-</span>
            </div>
            <div class="data-item">
                <span class="data-label">水平角:</span>
                <span class="data-value" id="current-azimuth">-</span>
            </div>
            <div class="data-item">
                <span class="data-label">俯仰角:</span>
                <span class="data-value" id="current-elevation">-</span>
            </div>
        </div>
        
        <div class="btn-group">
            <button class="btn btn-success" onclick="startRecording()">开始记录</button>
            <button class="btn btn-danger" onclick="stopRecording()">停止记录</button>
            <button class="btn" onclick="clearLog()">清空记录</button>
            <button class="btn" onclick="exportData()">导出数据</button>
        </div>
        
        <div id="data-log">
            <table>
                <thead>
                    <tr>
                        <th>时间</th>
                        <th>经度</th>
                        <th>纬度</th>
                        <th>高度</th>
                        <th>距离</th>
                        <th>水平角</th>
                        <th>俯仰角</th>
                    </tr>
                </thead>
                <tbody id="log-table-body">
                </tbody>
            </table>
        </div>
    </div>

    <script>
        /************************
         * 系统状态和全局变量
         ************************/
        var recordingInterval = null;
        var recordedData = [];
        var currentPoint = null;
        var Distance = 0;
        var speed = 10; // 无人机速度 m/s
        var isRecording = false;
        var azimuth = 0; // 水平角
        var elevation = 0; // 俯仰角
        var flightPathVisible = false; // 轨迹是否可见
        var flightPath = null; // 完整飞行轨迹线
        var currentFlightPath = null; // 当前飞行轨迹线
        var flightPathPoints = []; // 飞行轨迹点集合
        
        /************************
         * 工具函数
         ************************/
        // 更新时间显示
        function updateTime() {
            var now = new Date();
            var timeStr = now.toLocaleTimeString();
            document.getElementById('current-time').textContent = timeStr;
            return now;
        }
        
        // 格式化数字
        function formatNumber(num, decimals = 2) {
            return parseFloat(num.toFixed(decimals)).toLocaleString();
        }
        
        // 计算两点间距离
        function getDistanceByPixel(px1, px2) {
            if (!px1 || !px2) return 0;
            return Math.sqrt(Math.pow(px1.x - px2.x, 2) + Math.pow(px1.y - px2.y, 2));
        }
        
        // 计算水平角和俯仰角
        function calculateAngles(uavPosition) {
            // 计算相对坐标
            const dx = uavPosition.x - radarCenter.x;
            const dy = uavPosition.y - radarCenter.y;
            const dz = uavPosition.z - radarCenter.z;
            
            // 计算水平角 (azimuth) - 从正北方向顺时针计算
            azimuth = (Math.atan2(dx, dy) * 180 / Math.PI + 360) % 360;
            
            // 计算俯仰角 (elevation)
            const horizontalDistance = Math.sqrt(dx*dx + dy*dy);
            elevation = Math.atan2(dz, horizontalDistance) * 180 / Math.PI;
            
            return { azimuth, elevation };
        }
        
        /************************
         * 数据记录功能
         ************************/
        // 开始记录数据
        function startRecording() {
            if (isRecording) return;
            isRecording = true;
            recordingInterval = setInterval(recordCurrentData, 5000); // 每5秒记录一次
            console.log("开始记录无人机数据...");
            recordCurrentData(); // 立即记录一次
        }
        
        // 停止记录数据
        function stopRecording() {
            if (!isRecording) return;
            clearInterval(recordingInterval);
            isRecording = false;
            console.log("已停止记录");
        }
        
        // 清空记录
        function clearLog() {
            if (isRecording) {
                alert("请先停止记录再清空数据");
                return;
            }
            recordedData = [];
            document.getElementById('log-table-body').innerHTML = '';
            console.log("已清空记录");
        }
        
        // 导出数据为CSV
        function exportData() {
            if (recordedData.length === 0) {
                alert("没有可导出的数据");
                return;
            }
            
            let csvContent = "时间,经度,纬度,高度(米),距离(米),水平角(度),俯仰角(度)\n";
            recordedData.forEach(row => {
                csvContent += `${row.time},${row.lng},${row.lat},${row.alt},${row.dist},${row.azimuth},${row.elevation}\n`;
            });
            
            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.setAttribute('href', url);
            const filename = `无人机数据_${new Date().toISOString().slice(0,10)}.csv`;
            link.setAttribute('download', filename);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
        
        // 记录当前数据
        function recordCurrentData() {
            if (!currentPoint) return;
            
            var point = new BMapGL.Point(currentPoint.point.x, currentPoint.point.y);
            var commonPoint = BMapGL.Projection.convertMC2LL(point);
            var now = updateTime();
            
            // 计算角度
            const angles = calculateAngles(new THREE.Vector3(
                currentPoint.point.x,
                currentPoint.point.y,
                currentPoint.point.z
            ));
            
            var data = {
                time: now.toLocaleTimeString(),
                lng: commonPoint.lng.toFixed(6),
                lat: commonPoint.lat.toFixed(6),
                alt: currentPoint.point.z.toFixed(2),
                dist: Distance.toFixed(2),
                azimuth: angles.azimuth.toFixed(2),
                elevation: angles.elevation.toFixed(2)
            };
            
            recordedData.push(data);
            updateDataTable(data);
            console.log("记录数据:", data);
        }
        
        // 更新数据表格
        function updateDataTable(data) {
            const tableBody = document.getElementById('log-table-body');
            const row = document.createElement('tr');
            
            row.innerHTML = `
                <td>${data.time}</td>
                <td>${data.lng}</td>
                <td>${data.lat}</td>
                <td>${data.alt}</td>
                <td>${data.dist}</td>
                <td>${data.azimuth}°</td>
                <td>${data.elevation}°</td>
            `;
            
            tableBody.prepend(row); // 新数据添加到顶部
            
            // 限制显示的行数
            if (tableBody.children.length > 50) {
                tableBody.removeChild(tableBody.lastChild);
            }
        }
        
        // 更新当前数据显示
        function updateCurrentDataDisplay() {
            if (!currentPoint) return;
            
            var point = new BMapGL.Point(currentPoint.point.x, currentPoint.point.y);
            var commonPoint = BMapGL.Projection.convertMC2LL(point);
            
            // 计算角度
            const angles = calculateAngles(new THREE.Vector3(
                currentPoint.point.x,
                currentPoint.point.y,
                currentPoint.point.z
            ));
            
            document.getElementById('current-lng').textContent = commonPoint.lng.toFixed(6);
            document.getElementById('current-lat').textContent = commonPoint.lat.toFixed(6);
            document.getElementById('current-alt').textContent = formatNumber(currentPoint.point.z) + " 米";
            document.getElementById('current-dist').textContent = formatNumber(Distance) + " 米";
            document.getElementById('current-azimuth').textContent = angles.azimuth.toFixed(2) + "°";
            document.getElementById('current-elevation').textContent = angles.elevation.toFixed(2) + "°";
        }
        
        /************************
         * 地图和无人机功能
         ************************/
        // 初始化地图
        var map = new BMapGL.Map('map_container');
        
        // 无人机路径点
        var pois = [
            { x: 11572967.867287287, y: 3582744.2956278487, z: 20 },
            { x: 11573034.437067097, y: 3582743.3931161272, z: 20 },
            { x: 11573065.940825768, y: 3582703.811595824, z: 0 },
            { x: 11573039.891781494, y: 3582608.9196108533, z: 20 }
        ];
        
        // 麦克风矩阵固定坐标
        const radarCenter = new THREE.Vector3(
            11572967.867287287,
            3582744.2956278487,
            0
        );
        
        // 设置地图中心点和视角
        var point = new BMapGL.Point(pois[0].x, pois[0].y);
        var center = BMapGL.Projection.convertMC2LL(point);
        map.centerAndZoom(center, 20);
        map.setHeading(11);
        map.setTilt(60);
        
        // 启用地图控件
        map.enableKeyboard();
        map.enableScrollWheelZoom();
        map.enableInertialDragging();
        map.enableContinuousZoom();
        
        // 创建MapVGL视图
        var view = new mapvgl.View({ map: map });
        
        // 创建ThreeLayer用于3D效果
        var threeLayer = new mapvgl.ThreeLayer({ notUpdateSize: false });
        view.addLayer(threeLayer);
        
        // 创建麦克风矩阵扫描线
        const lineGeometry = new THREE.Geometry();
        lineGeometry.vertices.push(radarCenter);
        lineGeometry.vertices.push(new THREE.Vector3(radarCenter.x, radarCenter.y, 0));
        const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
        const line = new THREE.Line(lineGeometry, lineMaterial);
        threeLayer.add(line);
        
        // 更新麦克风矩阵线
        function updateLine(newDynamicPosition) {
            lineGeometry.vertices[1].x = newDynamicPosition.x;
            lineGeometry.vertices[1].y = newDynamicPosition.y;
            lineGeometry.vertices[1].z = newDynamicPosition.z;
            lineGeometry.verticesNeedUpdate = true;
        }
        
        // 创建麦克风矩阵点标记
        const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
        const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0x33dd33 });
        const radarPoint = new THREE.Mesh(sphereGeometry, sphereMaterial);
        radarPoint.position.set(radarCenter.x, radarCenter.y, radarCenter.z);
        threeLayer.add(radarPoint);
        
        // 创建飞行轨迹线
        function createFlightPath() {
            // 创建完整轨迹线的几何体
            const flightPathGeometry = new THREE.Geometry();
            
            // 添加路径点到几何体
            pois.forEach(point => {
                flightPathGeometry.vertices.push(new THREE.Vector3(point.x, point.y, point.z));
            });
            
            // 创建轨迹线材质
            const flightPathMaterial = new THREE.LineBasicMaterial({
                color: 0x00ffff,
                linewidth: 3,
                transparent: true,
                opacity: 0.8
            });
            
            // 创建轨迹线
            flightPath = new THREE.Line(flightPathGeometry, flightPathMaterial);
            flightPath.visible = false; // 初始不显示整条轨迹
            threeLayer.add(flightPath);
            
            // 创建当前飞行轨迹线(红色)
            const currentPathGeometry = new THREE.Geometry();
            currentPathGeometry.vertices.push(new THREE.Vector3(pois[0].x, pois[0].y, pois[0].z));
            
            const currentPathMaterial = new THREE.LineBasicMaterial({
                color: 0xff0000,
                linewidth: 2
            });
            
            currentFlightPath = new THREE.Line(currentPathGeometry, currentPathMaterial);
            threeLayer.add(currentFlightPath);
            
            // 创建轨迹点集合
            flightPathPoints = pois.map(point => new THREE.Vector3(point.x, point.y, point.z));
        }
        
        // 切换飞行轨迹显示状态
        function toggleFlightPath() {
            if (!flightPath) return;
            
            flightPathVisible = !flightPathVisible;
            flightPath.visible = flightPathVisible;
            
            // 更新按钮文本
            const button = document.querySelector('#tools button:nth-child(2)');
            button.textContent = flightPathVisible ? '隐藏完整轨迹' : '显示完整轨迹';
        }
        
        // 创建路径点插值函数
        function segLinePoints(pois) {
            var segTotalLength = [0];
            var segDegree = [0];
            
            for (var i = 1, length = pois.length; i < length; i++) {
                segTotalLength[i] = segTotalLength[i - 1] + getDistanceByPixel(pois[i], pois[i - 1]);
                segDegree[i] = 0.5 * Math.PI + Math.atan2(pois[i].y - pois[i - 1].y, pois[i].x - pois[i - 1].x);
            }
            
            return function (distance) {
                if (distance <= 0) {
                    return {
                        point: pois[0],
                        segDegree: segDegree[1],
                        index: 1
                    };
                }
                else if (distance >= segTotalLength[segTotalLength.length - 1]) {
                    if (fly) {
                        clearInterval(fly);
                        fly = null;
                    }
                    return {
                        point: pois[segTotalLength.length - 1],
                        segDegree: segDegree[segTotalLength.length - 1],
                        index: segTotalLength.length - 1
                    };
                }
                else {
                    var index = segTotalLength.findIndex(item => item > distance);
                    var startPoint = pois[index - 1];
                    var endPoint = pois[index];
                    var offsetRatio = (distance - segTotalLength[index - 1]) / (segTotalLength[index] - segTotalLength[index - 1]);
                    var x = startPoint.x + (endPoint.x - startPoint.x) * offsetRatio;
                    var y = startPoint.y + (endPoint.y - startPoint.y) * offsetRatio;
                    var z = startPoint.z + (endPoint.z - startPoint.z) * offsetRatio;
                    return {
                        point: { x, y, z },
                        segDegree: segDegree[index],
                        index: index
                    };
                }
            };
        }
        
        var calPoint = new segLinePoints(pois);
        
        // 创建Three.js时钟
        var clock = new THREE.Clock();
        var mixer;
        var flyGltf;
        var geoGroup;
        
        // 加载无人机模型
        let gltfLoader = new mapvgl.THREELoader.GLTFLoader();
        gltfLoader.load('UAV.glb', function (obj) {
            flyGltf = obj.scene;
            flyGltf.rotateX(90 / 180 * Math.PI);
            flyGltf.scale.set(2, 2, 2);
            
            geoGroup = new THREE.Group();
            geoGroup.add(flyGltf);
            geoGroup.position.x = point.lng;
            geoGroup.position.y = point.lat;
            geoGroup.position.z = pois[0].z;
            threeLayer.add(geoGroup);
            
            mixer = new THREE.AnimationMixer(obj.scene);
            const clip = obj.animations[0];
            const action = mixer.clipAction(clip);
            mixer.timeScale = 0.5;
            action.setDuration(2).play();
        });
        
        // 创建信息显示平面
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        const texture = new THREE.CanvasTexture(canvas);
        canvas.width = 500;
        canvas.height = 300;
        
        const geometry = new THREE.PlaneGeometry(20, 12);
        const material = new THREE.MeshBasicMaterial({
            map: texture,
            transparent: true,
        });
        
        const plane = new THREE.Mesh(geometry, material);
        threeLayer.add(plane);
        
        // 创建静态文字平面
        function createStaticPlane() {
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            canvas.width = 500;
            canvas.height = 300;
            
            context.font = '60px Arial';
            context.fillStyle = 'rgba(255,255,255,0.8)';
            context.fillText('麦克风矩阵', 5, 60);
            
            const texture = new THREE.CanvasTexture(canvas);
            const geometry = new THREE.PlaneGeometry(20, 12);
            const material = new THREE.MeshBasicMaterial({
                map: texture,
                transparent: true,
            });
            
            const plane2 = new THREE.Mesh(geometry, material);
            plane2.position.set(radarCenter.x, radarCenter.y, radarCenter.z);
            threeLayer.add(plane2);
            return plane2;
        }
        
        const plane2 = createStaticPlane();
        
        // 更新信息显示
        function updateCanvas() {
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.font = '60px Arial';
            context.fillStyle = 'rgba(255,255,255,0.8)';
            
            var point = new BMapGL.Point(currentPoint.point.x, currentPoint.point.y);
            plane.position.x = currentPoint.point.x;
            plane.position.y = currentPoint.point.y + 20;
            plane.position.z = currentPoint.point.z + 8;
            var commonPoint = BMapGL.Projection.convertMC2LL(point);
            
            const text = `维度: ${commonPoint.lat.toFixed(6)}`;
            const text2 = `经度: ${commonPoint.lng.toFixed(6)}`;
            const text3 = `高度: ${currentPoint.point.z.toFixed(2)} 米`;
            const text4 = `距离: ${Distance.toFixed(2)} 米`;
            
            context.fillText(text, 5, 60);
            context.fillText(text2, 5, 130);
            context.fillText(text3, 5, 200);
            context.fillText(text4, 5, 270);
            
            texture.needsUpdate = true;
        }
        
        // 更新麦克风矩阵坐标显示
        function updateRadarCoordsDisplay() {
            const radarPoint = new BMapGL.Point(radarCenter.x, radarCenter.y);
            const commonPoint = BMapGL.Projection.convertMC2LL(radarPoint);
            
            document.getElementById('radar-lng').textContent = `经度: ${commonPoint.lng.toFixed(6)}`;
            document.getElementById('radar-lat').textContent = `纬度: ${commonPoint.lat.toFixed(6)}`;
            document.getElementById('radar-alt').textContent = `高度: ${radarCenter.z.toFixed(2)} 米`;
        }
        
        // 无人机飞行控制
        var distance = 0;
        var dis = null;
        var fly = setInterval(function () {
            if (geoGroup) {
                distance += speed * 0.01;
                var result = calPoint(distance);
                currentPoint = result;
                geoGroup.position.x = result.point.x;
                geoGroup.position.y = result.point.y;
                geoGroup.position.z = result.point.z - 7;
                dis = map.getDistance(center, BMapGL.Projection.convertMC2LL(new BMapGL.Point(result.point.x, result.point.y)));
                Distance = Math.sqrt(dis * dis + result.point.z * result.point.z);
                updateLine(new THREE.Vector3(result.point.x, result.point.y, result.point.z));
                updateCanvas();
                geoGroup.rotation.z = result.segDegree;
                
                // 更新当前飞行轨迹
                if (currentFlightPath) {
                    currentFlightPath.geometry.vertices.push(new THREE.Vector3(result.point.x, result.point.y, result.point.z));
                    currentFlightPath.geometry.verticesNeedUpdate = true;
                }
                
                updateCurrentDataDisplay();
            }
        }, 15);
        
        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            if (mixer) mixer.update(clock.getDelta());
            if (plane) plane.lookAt(threeLayer.camera.position);
            if (plane2) plane2.lookAt(threeLayer.camera.position);
            threeLayer.update();
        }
        
        animate();
        
        // 跟踪无人机视角
        function targetToFly() {
            if (currentPoint) {
                var point = new BMapGL.Point(currentPoint.point.x, currentPoint.point.y);
                map.flyToIn(point, 20);
            }
        }
        
        // 初始化时间显示
        setInterval(updateTime, 1000);
        updateTime();
        
        // 初始化麦克风矩阵坐标显示
        updateRadarCoordsDisplay();
        
        // 创建飞行轨迹线
        createFlightPath();
    </script>
</body>
</html>